#include "../muduo/proto/pro.pb.h"
#include "../muduo/proto/codec.h"
#include "../muduo/proto/dispatcher.h"

#include <iostream>
#include <unordered_map>
#include <string>
#include <memory>
#include "Logging.h"
#include "Mutex.h"
#include "TcpServer.h"
#include "EventLoop.h"
#include "TcpConnection.h"

using namespace std;
using namespace muduo::net;

class Server // 仿造/home/ubuntu/resource/lib/muduo/examples/protobuf/codec/server.cc进行服务器编写
{
public:
    typedef shared_ptr<google::protobuf::Message> MessagePtr;
    typedef shared_ptr<pro::AddRequest> AddRequestPtr;
    typedef shared_ptr<pro::TranslateRequest> TranslateRequestPtr;
    Server(int port) : _server(&_baseloop, muduo::net::InetAddress("0.0.0.0", port), "Server", muduo::net::TcpServer::kReusePort),
                       _dispatcher(std::bind(&Server::onUnknownMessage, this, placeholders::_1, placeholders::_2, placeholders::_3)),
                       _codec(std::bind(&ProtobufDispatcher::onProtobufMessage, &_dispatcher, placeholders::_1, placeholders::_2, placeholders::_3))
    {
        // 注册业务处理回调
        _dispatcher.registerMessageCallback<pro::TranslateRequest>(std::bind(&Server::onTranslate, this,
                                                                             placeholders::_1, placeholders::_2, placeholders::_3)); // TranslateRequest类型消息：onTranslate回调
        _dispatcher.registerMessageCallback<pro::AddRequest>(std::bind(&Server::onAdd, this,
                                                                       placeholders::_1, placeholders::_2, placeholders::_3)); // AddRequest类型消息：onAdd回调

        // 绑定消息回调函数
        _server.setMessageCallback(std::bind(&ProtobufCodec::onMessage, &_codec,
                                             placeholders::_1, placeholders::_2, placeholders::_3));
        // 绑定连接回调函数
        _server.setConnectionCallback(std::bind(&Server::onConnection, this, placeholders::_1));

        LoadDict();
    }
    /*1.初始化分发器：绑定未定义消息类型处理回调
      2.初始化协议处理器：绑定分发器
      3.注册分发器上的业务处理函数
      4.设置消息回调，绑定协议处理器上的协议处理函数

      a.客户端发送消息，服务器调用消息回调，将消息传给协议处理器
      b.进行协议处理和获取消息类型后，交给分发器
      c.分发器根据注册的不同消息类型，分发给对应的业务处理函数
      d.处理后构建响应对象，交给协议处理器，去进行协议处理后发送*/
private:
    void onTranslate(const muduo::net::TcpConnectionPtr &conn, const TranslateRequestPtr &message, muduo::Timestamp)
    {
        // 1.提取message中有效消息（字段）
        string req_msg = message->msg();
        // 2.业务处理，得到结果
        string resp_msg = Translate(req_msg);
        // 3.构建响应
        pro::TranslateResponse resp;
        resp.set_msg(resp_msg);
        // 4.交给_codec进行协议处理（序列化）后，发回响应
        _codec.send(conn, resp);
    }
    void onAdd(const muduo::net::TcpConnectionPtr &conn, const AddRequestPtr &message, muduo::Timestamp)
    {
        int num1 = message->num1();
        int num2 = message->num2();

        pro::AddResponse resp;
        resp.set_result(num1 + num2);

        _codec.send(conn, resp);
    }
    void onUnknownMessage(const muduo::net::TcpConnectionPtr &conn, const MessagePtr &message, muduo::Timestamp)
    { // 收到未定义的消息类型时，回调处理
        cout << "onUnknownMessage:" << message->GetTypeName() << endl;
    }
    void onConnection(const muduo::net::TcpConnectionPtr &conn)
    {
        if (conn->connected())
            cout << "新连接建立成功" << endl;
        else
            cout << "连接关闭" << endl;
    }

public:
    void Start()
    {
        _server.start();
        _baseloop.loop();
    }

private:
    void LoadDict()
    {
        dict_map.insert(make_pair("hello", "你好"));
        dict_map.insert(make_pair("OK", "好的"));
        dict_map.insert(make_pair("abc", "ABC"));
        dict_map.insert(make_pair("banana", "芭拿拿"));
    }
    string Translate(const string &str)
    {
        auto iter = dict_map.find(str);
        if (iter == dict_map.end())
            return "unknown";
        return iter->second;
    }

private:
    muduo::net::EventLoop _baseloop; // 事件监控
    muduo::net::TcpServer _server;   // 服务器
    ProtobufDispatcher _dispatcher;  // 请求分发器：注册请求处理函数
    ProtobufCodec _codec;            // protobuf协议处理器：针对数据协议处理

    unordered_map<string, string> dict_map;
};

int main()
{
    Server server(8080);
    server.Start();
    return 0;
}